%module windbg

%include <windows.i>
%include <typemaps.i>

%{
#undef send
#include "stdafx.h"
#include "../common/ByteArray.h"
#include "../common/WindbgExt.h"

void FlushIo();

#ifndef __FUNCTION__
#define __FUNCTION__ "<unknown>"
#endif

%}

%include "../common/swig/declarations.i"

// parameter typemaps
%{
	template<typename T>
	int ByteArrayRef(SWIG_MAYBE_PERL_OBJECT SV *sv, PVOID& ptr, ULONG& bufSize)
	{
		void *byteArray;
		int res = SWIG_ConvertPtr(sv, &byteArray, SWIGTYPE_p_ByteArray, 0 | 0);
		if (!SWIG_IsOK(res))
			return res;
		if (byteArray != NULL)
		{
			ptr = reinterpret_cast<ByteArray*>(byteArray)->GetBuffer();
			bufSize = reinterpret_cast<ByteArray*>(byteArray)->Size() / sizeof(T);
		}
		else
		{
			ptr = NULL;
			bufSize = 0;
		}
		return 0;
	}
%}

// out typemaps to report interface absence
%typemap(out) const NoThrowException*
{
	if ($1 != NULL)
		SWIG_croak($1->what);
	$result = SWIG_NewPointerObj(SWIG_as_voidptr(NULL), SWIGTYPE_p_NoThrowException, 0 | 0);
	++argvi;
}

%typemap(out) void*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_long, 0 | 0);
	++argvi;
}

%typemap(out) IDebugAdvanced3*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugAdvanced3, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugClient7*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugClient7, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugControl7*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugControl7, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugDataSpaces4*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugDataSpaces4, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugRegisters2*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugRegisters2, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugSymbols5*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugSymbols5, 0 | SWIG_SHADOW);
	++argvi;
}

%typemap(out) IDebugSystemObjects4*
{
	if ($1 == NULL)
		SWIG_croak("No interface");
	$result = SWIG_NewPointerObj(SWIG_as_voidptr($1), SWIGTYPE_p_IDebugSystemObjects4, 0 | SWIG_SHADOW);
	++argvi;
}

// 64-bit integer references
%typemap(in) unsigned long long *REFERENCE (unsigned long long dvalue), unsigned long long &REFERENCE(unsigned long long dvalue),
			 unsigned __int64 *REFERENCE (unsigned __int64 dvalue), unsigned __int64 &REFERENCE(unsigned __int64 dvalue)
{
	SV *tempsv;
	if (!SvROK($input))
	{
		SWIG_croak("expected a reference");
	}
	tempsv = SvRV($input);
	if (!SvIOK(tempsv))
	{
		SWIG_croak("expected an integer reference");
	}
	dvalue = (unsigned long long) SvUV(tempsv);
	$1 = &dvalue;
} 

%typemap(typecheck) unsigned long long *REFERENCE, unsigned long long &REFERENCE,
					unsigned __int64 *REFERENCE, unsigned __int64 &REFERENCE
{
	$1 = SvROK($input);
	if($1)
	{
		SV *tmpsv = SvRV($input);
		$1 = SvUOK(tmpsv) || SvIOK(tmpsv);
	}
}

%typemap(argout) unsigned long long *REFERENCE, unsigned long long &REFERENCE,
				 unsigned __int64 *REFERENCE, unsigned __int64 &REFERENCE
{
	SV *tempsv;
	tempsv = SvRV($input);
	if (!$1) SWIG_croak("expected a reference");
	sv_setuv(tempsv, (UV) *$1);
} 

%typemap(in) (void* ptr, unsigned long size)
{
	int resByteArray = ByteArrayRef<BYTE>($input, $1, $2);
	if (!SWIG_IsOK(resByteArray))
		SWIG_exception_fail(SWIG_ArgError(resByteArray), "in method '" __FUNCTION__ "', argument $argnum of type '" "ByteArray *""'"); 
}

%typemap(in) (unsigned long* ptr, unsigned long size)
{
	int resByteArray = ByteArrayRef<ULONG>($input, *(reinterpret_cast<PVOID*>(&$1)), $2);
	if (!SWIG_IsOK(resByteArray))
		SWIG_exception_fail(SWIG_ArgError(resByteArray), "in method '" __FUNCTION__ "', argument $argnum of type '" "ByteArray *""'"); 
}

%typemap(in) (unsigned long size, unsigned long* ptr)
{
	int resByteArray = ByteArrayRef<ULONG>($input, *(reinterpret_cast<PVOID*>(&$2)), $1);
	if (!SWIG_IsOK(resByteArray))
		SWIG_exception_fail(SWIG_ArgError(resByteArray), "in method '" __FUNCTION__ "', argument $argnum of type '" "ByteArray *""'"); 
}

%typemap(in) (DEBUG_STACK_FRAME* ptr, unsigned long size)
{
	int resByteArray = ByteArrayRef<DEBUG_STACK_FRAME>($input, *(reinterpret_cast<PVOID*>(&$1)), $2);
	if (!SWIG_IsOK(resByteArray))
		SWIG_exception_fail(SWIG_ArgError(resByteArray), "in method '" __FUNCTION__ "', argument $argnum of type '" "ByteArray *""'"); 
}

%typemap(in) (PVOID Context, ULONG ContextSize) = (void* ptr, unsigned long size);
%typemap(in) (PVOID InBuffer, ULONG InBufferSize) = (void* ptr, unsigned long size);
%typemap(in) (PVOID OutBuffer, ULONG OutBufferSize) = (void* ptr, unsigned long size);
%typemap(in) (PVOID OptionsBuffer, ULONG OptionsBufferSize) = (void* ptr, unsigned long size);

%typemap(in) (ULONG Count, PULONG Types) = (unsigned long size, unsigned long* ptr);

%typemap(in) (PDEBUG_STACK_FRAME Frames, ULONG FramesSize) = (DEBUG_STACK_FRAME* ptr, unsigned long size);

// special for IDebugControl::OutputDisassemblyLines()
%typemap(in) (PULONG64 LineOffsets)
{
	ULONG bufSize;
	int resByteArray = ByteArrayRef<ULONG64>($input, *(reinterpret_cast<PVOID*>(&$1)), bufSize);
	if (!SWIG_IsOK(resByteArray))
		SWIG_exception_fail(SWIG_ArgError(resByteArray), "in method '" __FUNCTION__ "', argument $argnum of type '" "ByteArray *""'"); 
	if (($1 != NULL) && (bufSize < arg4))
		SWIG_croak("IDebugControl_OutputDisassemblyLines invalid argument: LineOffsets have to be large enough to hold TotalLines * sizeof(ULONG64) bytes");
}

%typemap(in) PDEBUG_BREAKPOINT Bp
{
	void *pobj;
    int res = SWIG_ConvertPtr($input, &pobj, SWIGTYPE_p_IDebugBreakpoint3, 0 | SWIG_POINTER_DISOWN);
    if (!SWIG_IsOK(res))
	{
		SWIG_exception_fail(SWIG_ArgError(res), "in method '" __FUNCTION__ "', argument $argnum of type '" "PDEBUG_BREAKPOINT""'"); 
    }
    $1 = reinterpret_cast<PDEBUG_BREAKPOINT>(pobj);
}

%typemap(in, numinputs=0) PDEBUG_BREAKPOINT *Bp (PDEBUG_BREAKPOINT temp)
{
	temp = NULL;
	$1 = &temp;
}

%typemap(argout) PDEBUG_BREAKPOINT *Bp
{
	$result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_IDebugBreakpoint3, 0 | ((*$1 == NULL) ? 0 : SWIG_OWNER) | SWIG_SHADOW);
	argvi++;
}

%typemap(in, numinputs=0) PDEBUG_BREAKPOINT3 *Bp (PDEBUG_BREAKPOINT3 temp)
{
	temp = NULL;
	$1 = &temp;
}

%typemap(argout) PDEBUG_BREAKPOINT3 *Bp
{
    $result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_IDebugBreakpoint3, 0 | ((*$1 == NULL) ? 0 : SWIG_OWNER) | SWIG_SHADOW);
	argvi++;
}

%typemap(in) PDEBUG_SYMBOL_GROUP Update
{
	void *pobj;
    int res = SWIG_ConvertPtr($input, &pobj, SWIGTYPE_p_IDebugSymbolGroup2, 0 | SWIG_POINTER_DISOWN);
    if (!SWIG_IsOK(res))
	{
		SWIG_exception_fail(SWIG_ArgError(res), "in method '" __FUNCTION__ "', argument $argnum of type '" "PDEBUG_SYMBOL_GROUP""'"); 
    }
    $1 = reinterpret_cast<PDEBUG_SYMBOL_GROUP>(pobj);
}

%typemap(in, numinputs=0) PDEBUG_SYMBOL_GROUP* Symbols (PDEBUG_SYMBOL_GROUP temp)
{
	temp = NULL;
	$1 = &temp;
}

%typemap(argout) PDEBUG_SYMBOL_GROUP* Symbols
{
    $result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_IDebugSymbolGroup2, 0 | ((*$1 == NULL) ? 0 : SWIG_OWNER) | SWIG_SHADOW);
	argvi++;
}

%typemap(in) PDEBUG_SYMBOL_GROUP2 Update
{
	void *pobj;
    int res = SWIG_ConvertPtr($input, &pobj, SWIGTYPE_p_IDebugSymbolGroup2, 0 | SWIG_POINTER_DISOWN);
    if (!SWIG_IsOK(res))
	{
		SWIG_exception_fail(SWIG_ArgError(res), "in method '" __FUNCTION__ "', argument $argnum of type '" "PDEBUG_SYMBOL_GROUP2""'"); 
    }
    $1 = reinterpret_cast<PDEBUG_SYMBOL_GROUP2>(pobj);
}

%typemap(in, numinputs=0) PDEBUG_SYMBOL_GROUP2* Symbols (PDEBUG_SYMBOL_GROUP2 temp)
{
	temp = NULL;
	$1 = &temp;
}

%typemap(argout) PDEBUG_SYMBOL_GROUP2* Symbols
{
    $result = SWIG_NewPointerObj(SWIG_as_voidptr(*$1), SWIGTYPE_p_IDebugSymbolGroup2, 0 | ((*$1 == NULL) ? 0 : SWIG_OWNER) | SWIG_SHADOW);
	argvi++;
}

%apply PDEBUG_SYMBOL_GROUP* Symbols {PDEBUG_SYMBOL_GROUP* Group};
%apply PDEBUG_SYMBOL_GROUP2* Symbols {PDEBUG_SYMBOL_GROUP2* Group};

%apply ULONG *REFERENCE {PULONG Options, PULONG Id, PULONG Code, PULONG Mask, PULONG Columns, PULONG Seconds, PULONG OffsetLine, PULONG OutSize,
	PULONG FoundElement, PULONG Number, PULONG Type, PULONG FramesFilled, PULONG Class, PULONG Qualifier, PULONG PlatformId, PULONG Major, PULONG Minor,
	PULONG ServicePackNumber, PULONG Size, PULONG Status, PULONG Level, PULONG Options, PULONG OutputLevel, PULONG BreakLevel, PULONG Radix,
	PULONG RemainderIndex, PULONG SpecificEvents, PULONG SpecificExceptions, PULONG ArbitraryExceptions, PULONG ProcessId, PULONG ThreadId,
	PULONG TimeDate, PULONG UpTime, PULONG FormatFlags, PULONG NumRepl, PULONG Flags, PULONG Events, PULONG DescSize, PULONG Index, PULONG NextIndex,
	PULONG SendsAttempted, PULONG SecondsSinceLastResponse, PULONG BreakType, PULONG ProcType, PULONG AccessType, PULONG Count, PULONG BytesRead,
	PULONG BytesWritten, PULONG Levels, PULONG Filled, PULONG ValidSize, PULONG TypeId, PULONG Line, PULONG Loaded, PULONG Unloaded, PULONG Offset,
	PULONG MatchSize, PULONG FoundElement, PULONG FieldTypeId, PULONG Register, PULONG Total, PULONG LargestProcess, PULONG SysId, PULONG UpTime,
	PULONG TotalThreads, PULONG TotalProcesses, PULONG LargestProcessThreads, PULONG LargestSystemThreads, PULONG LargestSystemProcesses};
%apply BOOL *REFERENCE {PBOOL Append};
%apply ULONG64 *REFERENCE {PULONG64 EndOffset, PULONG64 Offset, PULONG64 StartOffset, PULONG64 EndOffset, PULONG64 NearOffset, PULONG64 Handle,
	PULONG64 Arg1, PULONG64 Arg2, PULONG64 Arg3, PULONG64 Arg4, PULONG64 MatchOffset, PULONG64 Value, PULONG64 Physical, PULONG64 NextOffset,
	PULONG64 ValidBase, PULONG64 TypeModule, PULONG64 Displacement, PULONG64 Base, PULONG64 Module, PULONG64 InstructionOffset, PULONG64 Server};


%include "../common/swig/dbgeng.i"

%include "../common/swig/windbgext.i"
